home *** CD-ROM | disk | FTP | other *** search
-
- ;(load "scoops.fsl")
-
- (define extensions
- (let ((blanks (make-string 10 #\space)))
- (lambda (word w) ;word=string of 1 word followed by 1 blank
- ;w=window
- (let ((c (string-ref word 0))
- (word (substring word 1 (-1+ (string-length word)))))
- (case c
- (#\/ ;new term
- (window-set-attribute! w 'text-attributes (attr 'yellow))
- (display word w)
- (window-set-attribute! w 'text-attributes (attr))
- (display #\space w)
- #T)
- (#\@ ;emphasis
- (window-set-attribute! w 'text-attributes (attr 'red))
- (display word w)
- (window-set-attribute! w 'text-attributes (attr))
- (display #\space w)
- #T)
- (#\! ;break
- (fresh-line )
- (display word w)
- (display #\space w)
- #T)
- (#\] ;break and tab
- (fresh-line w)
- (display blanks w)
- (display word w)
- (display #\space w)
- #T)
- (else #F))))))
-
-
- ;;; the tutorial's frames ----------------------------------------
-
- (set! *tutorial*
- (make-tutorial
- 'name "SCOOPS"
- 'writeln-extensions extensions))
-
- (frame
- initial
- ("The tutorial will follow these conventions:"
- "-- words in /yellow introduce new terms"
- ; "-- words in @red mark notable points"
- "-- a happy-face character, like you see"
- "at the bottom of this screen,"
- "means Scheme is waiting on you to press a key"
- "-- and text in green is the item under discussion.")
- (:data "The SCOOPS Tutorial" :pp-data))
-
- (frame
- ()
- ("This tutorial starts with an introduction to"
- "object-oriented programming. Then it takes you through"
- "SCOOPS, showing how to code with it and introducing"
- "design principles appropriate to an object-oriented system."
- "When the"
- "tutorial is finished, you will have an opportunity to try your"
- "own hand at working with SCOOPS."
- ; "The classes for this tutorial are POINT, LINE and RECTANGLE."
- )
- ()
- ("Chapter 5 in the TI Scheme Language Reference Manual contains"
- "full information on SCOOPS."))
-
- (frame
- SCOOPS
- ("/SCOOPS stands for the /SCheme /Object-Oriented /Programming /System."
- "Object-oriented programming deals with the"
- "interactions of /objects, which have properties"
- "of data and code combined."
- "An object consists of variables, which are private to the object"
- "and contain its local state,"
- "and procedures, also private to the object, which define its behavior.")
- ()
- ()
- ()
- "Introduction to Object-Oriented Programming"
- ("object" "SCOOPS"))
-
- (frame
- ()
- ("You communicate with an object by sending it a /message, which"
- "is somewhat like a procedure call."
- "The object responds by executing one of its"
- "local procedures and returning a value to"
- "the caller.")
- ()
- ("Unlike conventional languages where the caller directly invokes"
- "a procedure by using its name, the object approach allows the"
- "object to substitute any procedure it sees fit that can perform"
- "the task that the message names--the caller"
- "cannot force it to call a specific procedure.")
- ()
- ()
- ("message"))
-
- (frame
- ()
- ("What we've really done is swap the roles of who's controlling who."
- "In conventional languages, the caller has control over"
- "what procedures get executed with what data."
- "In the object-oriented approach, the data decides"
- "what procedures it will use on itself, and uses the message mechanism"
- "to keep the caller from knowing the details about how it"
- "did it.")
- ()
- ("This is the fundamental point of a message."
- "It requests some kind of action on the object's part, but"
- "the wording of the message implies nothing about how it"
- "performs the action. This gives an object great flexibility"
- "in how it is implemented, and it greatly enhances the"
- "modularity of the system.")
- ()
- ()
- ("message"))
-
- (frame
- ()
- ("How does one build an object?"
- "First you declare the kind of object you want;"
- "this is called the object's /class."
- "Defining a class is somewhat like defining a \"record\" or \"structure\""
- "in a conventional language--it declares what an object looks like,"
- "but it doesn't actually create one."
- "A class definition will include things like:"
- "-- the name of the class"
- "-- what variables are local to the object and what ones can it reference"
- "-- what are their default values"
- "-- declarations of simple local procedures"
- "-- the inheritance structure of the class."
- "This last is a very powerful feature of an object-oriented system,"
- "and we will come back to it later.")
- ()
- ()
- ()
- ()
- ("class"))
-
- (frame
- ()
- ("Now, using the class description, we can create as many objects"
- "of that kind as we wish."
- "A created object is called an /instance."
- "It takes up memory space, keeps its own state, and knows"
- "what kind of object it is (its class)."
- "In a conventional language, this is akin to dynamically allocating space"
- "for a \"record\" variable.")
- ()
- ("Incidentally, the variables local to each instance are called"
- "/instance /variables."
- "One way to distinguish one instance from another is to look"
- "at the state information contained in the instance variables."
- "That is, of course, if the object will let us look at them.")
- ()
- ()
- ("instance" "instance variable"))
-
- (frame
- ()
- ("Some object-oriented systems allow only instance variables;"
- "that is, an instance cannot refer to any other variables than its own."
- "Other systems allow varying degrees of freedom in where an instance"
- "can look."
- "For example, SCOOPS allows /class /variables."
- "These are variables maintained by the class itself rather than"
- "by each instance."
- "Data that would be common to every instance can be factored out"
- "into the class and stored just once, rather than repeating it"
- "in every instance."
- "It also provides a way for an instance to transfer data to other"
- "similar instances.")
- ()
- ()
- ()
- ()
- ("class variable" ))
-
- (frame
- ()
- ("So far what we've said makes objects sound very much like"
- "conventional data structures such as records."
- "But objects are not just places that hold variables--they hold"
- "code too."
- "These are the local procedures, or /methods, of an object."
- "They're called methods to distinguish them from procedures"
- "in a conventional language, which can be directly invoked by name."
- "Methods cannot be directly invoked."
- "Instead, an object, upon getting a message, decides what method"
- "gets invoked."
- "This determination can get quite involved, as you will see;"
- "a conventional language has nothing quite like it.")
- ()
- ()
- ()
- ()
- ("method"))
-
- (frame
- ()
- ("Unlike instance variables, which must all be declared in"
- "a class declaration, so that every instance gets the same set,"
- "methods can be added anytime to a class."
- "Methods are local to a class, really, rather than each instance,"
- "and so the code exists in the class, avoiding duplication for"
- "each instance."
- "More importantly, when a method is added or altered, all instances"
- "\"see\" the effects immediately.")
- ()
- () ;slot for text below
- ; ("For the record, to show some of the possibilities,"
- ; "some object-oriented systems"
- ; "actually do allow \"instance methods\"."
- ; "The \"ultimate\" architecture for an object-oriented programming"
- ; "system has yet to be determined.")
- ()
- ()
- ("method"))
-
- (frame
- ()
- ("You've probably noticed that sometimes we're a little sloppy"
- "in our terminology, for example, confusing \"instance\" and \"object\"."
- "An \"object\" is really an abstract entity while an \"instance\""
- "is its realization on a computer, but in practice everyone knows"
- "what you mean."
- "The words \"program\" and \"algorithm\" are also often used"
- "interchangeably; it's no different here.")
- ()
- ("Similarly, we've talked about instances having \"instance variables\""
- "and \"methods\"."
- "Looked at abstractly, an instance does have these properties."
- "On a real machine, though, it'd be real expensive if each instance"
- "had to have its own copy of its methods, and so the implementation"
- "collects them in the class to save space."
- "But that is the implementor's worry and shouldn't be yours."
- "The whole idea of objects is that you can't peer inside one."
- "If you could seriously take advantage of what you might find there,"
- "then it only indicates that the implementation must leave"
- "something to be desired.")
- ()
- ()
- ("instance" "object" "method" "abstraction vs. implementation"))
-
- (frame
- ()
- ("Now that you've got the general idea, let's get acquainted with SCOOPS"
- "so that you can see objects in action and how you go about"
- "constructing a program with objects."))
-
- (frame
- CLASS
- ("Objects often model real-world items."
- "For the tutorial, we will construct a \"graphics world\""
- "populated with shapes like points, lines, and rectangles."
- "We will model the kinds of shapes with classes, and"
- "individual shapes will be instances of those classes."
- "To start out, then, we use the special form /DEFINE-CLASS"
- "to create a class."
- "For example:")
- (:eval (or (getprop 'define-class 'pcs*macro)
- (load "scoops.fsl"))
- :data (define-class point (instvars (x 0) (y 0)))
- :data-eval :pp-data)
- ("This defines a class named \"POINT\". Each instance of the class"
- "contains two instance variables called X and Y, and each"
- "is initialized to zero."
- "! !This form of the definition allows us to create instances,"
- "but that's all."
- "We cannot create them with different initial values,"
- "and once created, we cannot look at or change them in any way.")
- ()
- "Defining a Class"
- ("DEFINE-CLASS"))
-
- (frame
- ()
- ("Let's explore some of the possibilities of DEFINE-CLASS."
- "First let's change POINT's definition so that we can create"
- "points whose X and Y values won't always be zero."
- "It would be rather dull to have all our points"
- "be synonymous with the origin.")
- (:data (define-class point (instvars (x 0) (y 0))
- (options inittable-variables)) :data-eval :pp-data)
- ("The /inittable-variables option allows us to override"
- "the default instance variable values whenever we create a point."
- "The form used allows all of them to be initialized."
- "If there is some reason to restrict which variables can be"
- "initialized, instead of saying \"inittable variables\""
- "we could have said something like \"(inittable variables x)\","
- "which would allow only X to be initialized--Y would always get"
- "its default value.")
- ()
- ()
- ("inittable-variables" "class options"))
-
- (frame
- ()
- ("So far we can create points,"
- "but we can't do anything with the X,Y values."
- "They are inside a point object and are hidden to any caller."
- "To do anything further requires object-local procedures--methods--to"
- "handle the point's representation for the outside world."
- "! !The simplest methods are those that just retrieve instance"
- "variable values and return them. They are so simple, in fact,"
- "that SCOOPS can create them on its own.")
- (:data (define-class point (instvars (x 0) (y 0))
- (options gettable-variables inittable-variables)) :data-eval :pp-data)
- ("We have a new option, /gettable-variables."
- "This creates two messages, GET-X and GET-Y;"
- "two methods, one to retrieve X and one to retrieve Y,"
- "and associates the methods with the messages."
- "As before, we can restrict which instance variables"
- "get the gettable methods.")
- ()
- ()
- ("gettable-variables" "class options"))
-
- (frame
- ()
- ("For the final touch, let's be able to change the instance variables."
- "We have a new option.")
- (:data (define-class point (instvars (x 0) (y 0))
- (options settable-variables
- gettable-variables
- inittable-variables)) :data-eval :pp-data)
- ("The /settable-variables option creates the messages SET-X and SET-Y,"
- "methods to change X and Y, and associates them."
- "Here, too, we can restrict which instance variables are settable.")
- ()
- ()
- ("settable-variables" "class options"))
-
- (frame
- ()
- ("You should note that the different options are mutually exclusive."
- "You can have settable but not gettable variables, settables but"
- "not inittables, or any other combination. And if you have no options"
- "you get immutable objects that can't be initialized, examined, or"
- "altered.")
- ()
- ("We should emphasize that"
- "the notions of \"gettable\", \"settable\", and \"inittable\" are all"
- "relative to what a caller sees."
- "To the object's own methods, the instance variables are always"
- "accessible at all times with no restrictions."
- "This will be clearer when we define a method ourselves rather"
- "than letting the system do it.")
- ()
- ()
- ("settable-variables" "gettable-variables" "inittable-variables"
- "class options"))
-
- (frame
- ()
- ("Although we haven't exhausted all the features of DEFINE-CLASS,"
- "let's move on."
- "We'll explore more of them as we need them."))
-
- (frame
- ()
- ("Let's detour for a moment."
- "We've being redefining our class so much, what does it really"
- "look like at this moment?"
- "Using /(DESCRIBE class-name) will tell us."
- "Here's what it says for POINT.")
- (:output (DESCRIBE POINT))
- ("The class name, instance variables, and methods we have already described;"
- "the other items we have yet to discuss."
- "DESCRIBE doesn't indicate which variables are initializable,"
- "nor which methods are automatically generated.")
- ()
- ()
- ("DESCRIBE"))
-
- (frame
- COMPILE-CLASS
- ("Before we can create instances, we need to /compile the class."
- "We don't mean here that we generate code for the class,"
- "but rather we (re)organize the class's inheritance structure"
- "for efficient execution."
- "This can take time, depending on the complexity of the"
- "inheritance structure."
- "We don't have to do anything special, since the class"
- "can be compiled when its first instance is made."
- "Often, though, we know the class's complete inheritance structure"
- "at compile (as in \"generate code\") time."
- "If so, we can let the compiler compile the class."
- "Then the system needn't do it while executing the program."
- "We can use the special forms COMPILE-CLASS to compile the class"
- "and CLASS-COMPILED? to see whether it has been or not.")
- (:data (COMPILE-CLASS POINT) :data-eval :pp-data
- :eval (fresh-line)
- :data (CLASS-COMPILED? POINT) :data-eval :pp-data :yields :pp-evaled-data)
- ()
- ()
- ()
- ("compiling a class" "COMPILE-CLASS" "CLASS-COMPILED?"))
-
- (frame
- MAKE-INSTANCE
- ("To create an instance of a class you use the special form"
- "MAKE-INSTANCE. The simplest format of it is:")
- (:data (DEFINE P1 (MAKE-INSTANCE POINT)) :data-eval :pp-data)
- ("We've created a POINT instance and assigned it to variable P1."
- "Since we said nothing special about initializing anything,"
- "X and Y get their default values of zero.")
- ()
- "Defining Instances"
- ("MAKE-INSTANCE" "creating instances"))
-
- (frame
- ()
- ("To verify what we just said, we can DESCRIBE an instance as well"
- "as a class."
- "\"(DESCRIBE P1)\" gives this output:")
- (:output (DESCRIBE P1))
- ("This tells us which class the object is an instance of"
- "and the values of all the variables it can access.")
- ()
- ()
- ("DESCRIBE"))
-
- (frame
- ()
- ("We can create arbitrary points by initializing them with"
- "appropriate X and Y values.")
- (:data (define p2 (make-instance point 'y 10)) :data-eval :pp-data
- :eval (fresh-line)
- :data (define p3 (make-instance point 'x 5 'y 15)) :data-eval :pp-data)
- ("For point P2 we initialized Y but let X default to zero."
- "For point P3 we initialized everything."
- "! !The next frame has DESCRIBE's of P2 and P3.")
- ()
- ()
- ("MAKE-INSTANCE"))
-
- (frame
- ()
- ()
- (:output (describe p2) :output (describe p3)))
-
- (frame
- SEND
- ("In order to change the values of X and Y we would send a message to P1"
- "specifying the method we want to use to manipulate the data. For example,"
- "the command:")
- (:data (SEND P1 SET-X 50) :data-eval :pp-data)
- ("would change the value of X from 0, the initial value, to"
- "50.")
- ()
- "Sending Messages")
-
- (frame
- DEFINE-METHOD
- ("To define a method for a class you would use the special form"
- "/DEFINE-METHOD. Let's define a method to display the instances of"
- "the point class we've created. For example:")
- (:data (DEFINE-METHOD (POINT DRAW) () (DRAW-POINT X Y)) :data-eval :pp-data)
- ("What we would have to do now is to send two messages, one"
- "to change the value of X or Y and another to draw the point."
- "This would be fine if we only wanted to put points on the"
- "screen that were the same color and didn't mind old occurances"
- "hanging around.")
- ()
- "Defining Methods")
-
- (frame
- ()
- ("First we can modify the class definition to include color. This is"
- "simply adding another instance variable to be used to define the"
- "color. Our class \"POINT\" could now be defined as:")
- (:data (define-class point
- (instvars (x 0)
- (y 0)
- (color 7))
- (options settable-variables))
- :data-eval :pp-data)
- ("Now we have another method defined for us, SET-COLOR. And we can"
- "manipulate the COLOR variable as we have manipulated the X variable."
- "The problem of having to send two messages, one to set the value and"
- "the other to draw the point still exists, however."))
-
- (frame
- ACTIVE-VALUES
- ("We can modify the class definition to include /ACTIVE /VALUES."
- "Active values are used to trigger procedure invocations whenever"
- "the value of the variable is accessed or updated. The special form"
- "-\"(ACTIVE 'INITIAL-VALUE' 'GET-FN' 'SET-FN')\" is used. Now when"
- "we use SET-X, SET-X will call the \"set-fn\" and perform whatever action"
- "that method indicates and will set the X to whatever value the"
- "\"set-fn\" returns. Our class definition is now:")
- (:data (define-class point
- (instvars (x (active 0 () move-x))
- (y (active 0 () move-y))
- (color (active 7 () change-color))))
- :data-eval :pp-data)
- ("Active values are automatically gettable and settable so we don't need to"
- "specify those options.")
- ()
- "Active Values")
-
- (frame
- ()
- ("Now when we send a message to P1 to set X to some"
- "value, the procedure MOVE-X is called automatically."
- "Of course we still need to"
- "write the procedures MOVE-X, MOVE-Y and CHANGE-COLOR.")
- (:data (compile-class point) :data-eval))
-
-
- (frame
- ()
- ("For example we will define the MOVE-Y method. First we will define"
- "an ERASE method to erase the previous position of the point and then"
- "we will define a REDRAW method to redraw the point in its new location.")
- (:data (define-method (point erase) () (set-pen-color! 'black)
- (draw-point x y)) :data-eval :pp-data :fresh-line
- :data (define-method (point redraw) () (set-pen-color! color)
- (draw-point x y)) :data-eval :pp-data :fresh-line
- :data (define-method (point move-y) (new-y) (erase) (set! y new-y)
- (redraw) new-y) :data-eval :pp-data)
- ())
-
- (frame
- ()
- ("The methods for MOVE-X and CHANGE-COLOR would be very similar to MOVE-Y"
- "now that we have the ERASE and REDRAW methods."
- "-We could, if we wanted, send a message to P1 and have the"
- "X value changed two ways. Either you can send a message to the"
- "MOVE-X method with a new value to which to set the variable or you"
- "can send a message to the SET-X method with a value and let Scheme"
- "call the MOVE-X method automatically.")
- (:data (define p1 (make-instance point)) :data-eval
- :data (send p1 move-y -50) :data-eval :pp-data :fresh-line
- :data (send p1 set-y -50) :data-eval :pp-data
- :data (send p1 erase) :data-eval)
- ("These two calls are equivalent since SET-Y will automatically call"
- "MOVE-Y."))
-
- (frame
- INHERITANCE
- ("Another powerful feature of object oriented programming is"
- "/inheritance. Classes can inherit variables from previously"
- "defined classes. For example the class \"LINE\" can inherit the"
- "variables X, Y and COLOR from \"POINT\", and only need to define"
- "length and direction. For example:")
- (:data (define-class line
- (instvars (len (active 50 () change-length))
- (dir (active 0 () change-direction)))
- (mixins point))
- :data-eval :pp-data)
- ("Remember that for active values there is no need to specify options."
- "The set and get methods are automatically generated. If we had some"
- "procedure to be performed by the get-function, besides returning the"
- "current value, then we could"
- "specify a method to be executed automatically by substituting the"
- "name where the \"()\" is before the set-function name.")
- ()
- "Inheritance")
-
- (frame
- ()
- ("In addition to inheriting variables from other classes, methods"
- "are also inherited. This means that we do not have to define an"
- "erase method, we inherited it from \"POINT\". In fact the only methods"
- "we have to define are CHANGE-LENGTH, CHANGE-HEIGHT and DRAW."
- "We need our own draw method to draw a line instead of a point."
- "The practice of writing your methods to be as general as"
- "possible facilitates the inheritance feature."))
-
- (frame
- ()
- ("Having defined the CHANGE-LENGTH and CHANGE-DIRECTION methods,"
- "we could modify the LINE by sending messages to the SET-LEN"
- "and SET-DIR methods. If we then decide to change LINE to be another"
- "set of X and Y coordinates, instead of a length and direction,"
- "we could modify CHANGE-LENGTH to calculate the new position."
- "Since CHANGE-LENGTH is called automatically by SET-LEN, the user"
- "code would not"
- "have to be changed. It would keep sending a message to SET-LEN"
- "with a new length and never know that we modified two variables and"
- "changed the representation of line. This is another powerful"
- "feature of object oriented programming, the ability to change"
- "the way the data is structured and not have to change the user"
- "program!"))
-
- (frame
- CONCLUSION
- ("You may want to print out the file scpsdemo.s, if you haven't already"
- "done so, and look at the definitions of the classes. You"
- "will notice that the class \"RECTANGLE\" inherits \"POINT's\""
- "variables indirectly by inheriting \"LINE\".")
- ()
- ("Following this tutorial there is a demonstration using the class"
- "\"RECTANGLE\". During the demonstration it is not possible to go"
- "backwards, only forwards. A light touch on the keyboard is advised.")
- ()
- "Conclusion")
-
-